9.2. XML

    Jersey 目前支持一些低水平的数据类型:StreamSource, , DOMSource 和 。您可以使用这些类型的返回类型或方法(资源)参数。让说我们想要测试这个功能,我们有 helloworld示例 作为起点。所有我们需要做的就是添加方法(资源)的消耗和产生的 XML 和类型将使用上面提到的。

    Example 8.31. Low level XML test - methods added to HelloWorldResource.java

    MessageBodyWriter 和 MessageBodyReader 都在这个例子中使用了,我们需要的是一个 POST 请求 XML 文档作为一个请求的实体。让这只尽可能简单的根元素没有内容将发送:“”。您可以创建 JAX-RS 客户端,或使用其他一些工具,例如 curl:

    你应该从我们的服务得到完全相同的 XML ;在本例中,XML 头添加到响应但内容停留。自由的遍历所有资源。

    好的开始,人们已经有了一些 JAXB 注解的经验,例子是是 。你可以看到不同的用例。本文主要是针对那些没有 JAXB 经验。别指望所有可能的注释和他们的组合将在这一章,JAXB(JSR 222实现)是相当复杂和全面。但如果你只是想知道如何与 REST 服务交换 XML 消息,你看着合适的章节。

    可以从简单的例子开始。让我们说我们有类 Planet 和服务生产的“Planets”。

    Example 9.32. Planet class

    1. public class Planet {
    2. public int id;
    3. public String name;
    4. public double radius;
    5. }

    Example 9.33. Resource class

    1. @Path("planet")
    2. public class Resource {
    3. @GET
    4. @Produces(MediaType.APPLICATION_XML)
    5. public Planet getPlanet() {
    6. final Planet planet = new Planet();
    7. planet.id = 1;
    8. planet.name = "Earth";
    9. planet.radius = 1.0;
    10. return planet;
    11. }
    12. }

    我们的资源类将响应 GET/planet 请求

    1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    2. <planet>
    3. <id>1</id>
    4. <name>Earth</name>
    5. <radius>1.0</radius>
    6. </planet>

    这可能正是我们想要的……与否。或者我们可能不关心,因为我们可以使用 JAX-RS 客户端发出请求该资源,这很容易:

    有预先创建 WebTarget 对象指向我们的应用程序的上下文根,只需添加路径(在我们的例子中是planet),接收 header(不是强制性的,但服务可以提供不同的内容基于这头,例如可以为 text/html 在 web 浏览器),最后我们指定,我们预计 Planet 类通过GET请求。

    不仅可能需要生成 XML ,我们可能希望使用它。

    Example 9.34. Method for consuming Planet

    1. @POST
    2. @Consumes(MediaType.APPLICATION_XML)
    3. System.out.println("setPlanet " + planet);
    4. }

    有效的请求后,服务将打印字符串表示的 Planet,可以像 Planet{id=2, name=’Mars’, radius=1.51}。通过 JAX-RS 客户端你能做到:

    1. webTarget.path("planet").post(planet);

    如果有需要其他(非默认的) XML 表示,其他 JAXB 注解需要被使用。简化这一过程通常是由从 XML 模式生成 java 源代码是通过 XML 到 java 编译器和它的 xjc 是 JAXB 的一部分。

    有时,你不能或者不想在代码里面使用注解,但又想用消费和生成 XML 的类的表现形式。这种情况下就可以用 。下面例子就是没有用 @XmlRootElement 注解:

    Example 9.35. Resource class - JAXBElement

    1. @Path("planet")
    2. @GET
    3. @Produces(MediaType.APPLICATION_XML)
    4. public JAXBElement<Planet> getPlanet() {
    5. Planet planet = new Planet();
    6. planet.id = 1;
    7. planet.name = "Earth";
    8. planet.radius = 1.0;
    9. return new JAXBElement<Planet>(new QName("planet"), Planet.class, planet);
    10. }
    11. @POST
    12. @Consumes(MediaType.APPLICATION_XML)
    13. public void setPlanet(JAXBElement<Planet> planet) {
    14. System.out.println("setPlanet " + planet.getValue());
    15. }
    16. }

    Example 9.36. Client side - JAXBElement

    有些场景适合使用自定义 。JAXBContext 的创建是一个昂贵的操作,如果你已经创建了一个,相同的实例被 Jersey 使用。其他可能使用的情况是当你需要给 JAXBContext 建立一些特定的东西,例如设置不同的类装载器。

    Example 9.37. PlanetJAXBContextProvider

    1. @Provider
    2. public class PlanetJAXBContextProvider implements ContextResolver<JAXBContext> {
    3. private JAXBContext context = null;
    4. public JAXBContext getContext(Class<?> type) {
    5. if (type != Planet.class) {
    6. return null; // we don't support nothing else than Planet
    7. }
    8. if (context == null) {
    9. context = JAXBContext.newInstance(Planet.class);
    10. // log warning/error; null will be returned which indicates that this
    11. // provider won't/can't be used.
    12. }
    13. }
    14. return context;
    15. }
    16. }

    上面示例简单创建 JAXBContext 的过程,所有你需要做的就是把这个@Provider 注释放上,这样 Jersey 就能找到它。用户有时在客户端使用 provider (提供者)类 出问题,所以只是为了提醒——你必须 在客户端配置(客户端做任何事情不像通过服务器包扫描)声明他们。

    Example 9.38. Using Provider with JAX-RS client

    1. ClientConfig config = new ClientConfig();
    2. config.register(PlanetJAXBContextProvider.class);
    3. Client client = ClientBuilder.newClient(config);

    如果你想使用 作为 JAXB 实现而不是 JAXB RI 您有两种选择。您可以使用标准的 JAXB 机制来定义 从 JAXBContext 实例将获得(有关此主题的更多信息,读JavaDoc JAXBContext)的 JAXBContextFactory 或者你可以将 jersey-media-moxy 模块添加到您的项目和注册/配置 类/实例的Configurable

    Example 9.39. Add jersey-media-moxy dependency.

    1. <dependency>
    2. <groupId>org.glassfish.jersey.media</groupId>
    3. <artifactId>jersey-media-moxy</artifactId>
    4. <version>2.16</version>
    5. </dependency>

    Example 9.40. Register the MoxyXmlFeature class.

    Example 9.41. Configure and register an MoxyXmlFeature instance.

    1. // Configure Properties.
    2. final Map<String, Object> properties = new HashMap<String, Object>();
    3. // ...
    4. // Obtain a ClassLoader you want to use.
    5. final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    6. final ResourceConfig config = new ResourceConfig()
    7. .packages("org.glassfish.jersey.examples.xmlmoxy")
    8. .register(new MoxyXmlFeature(
    9. properties,
    10. classLoader,
    11. true, // Flag to determine whether eclipselink-oxm.xml file should be used for lookup.
    12. CustomClassA.class, CustomClassB.class // Classes to be bound.
    13. ));